/*NOTICE

This software was produced for the U. S. Government
under Contract No. FA8721-09-C-0002, and is
subject to the Rights in Noncommercial Computer Software
and Noncommercial Computer Software Documentation Clause
(DFARS) 252.227-7014 (JUN 1995)

(c) 2009 The MITRE Corporation. All Rights Reserved.
*/
package org.mitre.xmltransform.uml21tospmif4;

import java.util.ArrayList;
//import java.util.Iterator;
import java.util.List;

import org.mitre.xmltransform.spmif.Device;
//import org.mitre.xmltransform.spmif.HierarchyStep;
import org.mitre.xmltransform.spmif.SpmifOutputDocument;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class HierarchalNode extends BaseNode {
	public HierarchalNode(String pId, String pName, Device pLocation, String pExecutesOn, String pInitiatedOn, String pDuration, Node pMessageNode, NodeHierarchy pNodeHierarchy, boolean pAsync) {
		super(pId, pName, pExecutesOn, pInitiatedOn, pNodeHierarchy, pLocation);
		mChildren = new ArrayList<BaseNode>();
		mDuration = pDuration;
		mMessageNode = pMessageNode;
		mExecutionGraphElement = null;
		mAsync = pAsync;
	}
		
	public boolean canHaveChildren() {
		return true;
	}
	public void addChild(BaseNode pChild) {
		mChildren.add(pChild);
	}
	public String getDuration() {
		if (mDuration == null) {
			return "0.0";
		} else {
			return mDuration;
		}
	}
		
	public String getOutermostSpmifId() {
		if (hasChildren()) {
			if (mAsync) {
				return "Split" + getIdNumber();
			}
			return "REF" + getIdNumber();
		}
		return "EXEC" + getIdNumber();
	}
	
	public String getSpmifId() {
		if (hasChildren()) {
			return "REF" + getIdNumber();
		}
		return "EXEC" + getIdNumber();
	}
	
	@Override
	public void generateStep(Element pParentElement, SpmifOutputDocument pOutput) {
		BaseNode child;
		String name = getName();
		Element parent;
		
		if (hasChildren()) {
			Element splitNode;
			if (mAsync) {
				splitNode = pOutput.addElement(pParentElement, "SplitNode", null);
				splitNode.setAttribute("NodeName", getOutermostSpmifId());
				parent = splitNode;
			} else {
				parent = pParentElement;
			}
			Element expandedNode = pOutput.addElement(parent, "ExpandedNode", null);
			expandedNode.setAttribute("NodeName", name);
			expandedNode.setAttribute("NodeId", getSpmifId());
			if (name == null) throw new IllegalArgumentException("must provide the EG id");
			expandedNode.setAttribute("EGId", name);
			expandedNode.setAttribute("EGname", name);
			
			
			mExecutionGraphElement = pOutput.createExecutionGraph(
					getNodeHierarchy().getPerformanceScenarioElement(), name, name, false);

			for (int i = 0; i < mChildren.size(); i++) {
				child = mChildren.get(i);
				if (i == 0) {
					// start node
					mExecutionGraphElement.setAttribute("StartNode", child.getOutermostSpmifId());
				}
				child.generateStep(mExecutionGraphElement, pOutput);
			}
		} else {
			Element basicNodeElem = pOutput.addElement(pParentElement, "BasicNode", null);
			basicNodeElem.setAttribute("NodeName", name);
			basicNodeElem.setAttribute("NodeId", getOutermostSpmifId());
			
			if (getDuration() != null) {
				Element rr = pOutput.addElement(basicNodeElem, "ResourceRequirement", null);
				rr.setAttribute("ResourceId", "R" + getLocation().getName());
				rr.setAttribute("UnitsOfService", getDuration());
			}			
		}
	}
	
	@Override
	public String generateArcs(Element pParentElement, String pFromNode, SpmifOutputDocument pOutput) {
		BaseNode child;
		Element arcNode;
		//String id = getSpmifId();
		String id = getOutermostSpmifId();
		
		if (hasChildren()) {
			//if (mAsync) {
				//id = "Split" + getIdNumber();
			//}
			if (pFromNode != null) {
				arcNode = pOutput.addElement(pParentElement, "Arc", null);
				arcNode.setAttribute("FromNode", pFromNode);
				arcNode.setAttribute("ToNode", id);
			}
			
			String fromNode = null;
			for (int i = 0; i < getNumberOfChildren(); i++) {
				child = getChild(i);
				fromNode = child.generateArcs(mExecutionGraphElement, fromNode, pOutput);
			}

			return id;
		} else {
			if (pFromNode != null) {
				arcNode = pOutput.addElement(pParentElement, "Arc", null);
				arcNode.setAttribute("FromNode", pFromNode);
				arcNode.setAttribute("ToNode", id);
			}
			return id;
		}
	}

	public boolean hasChildren() {
		return mChildren.size() > 0;
	}
	public int getNumberOfChildren() {
		return mChildren.size();
	}
	public BaseNode getChild(int pIndex) {
		return mChildren.get(pIndex);
	}
	public Node getUMLMessageNode() {
		return mMessageNode;
	}
	
	private boolean mAsync;
	private Element mExecutionGraphElement;
	private Node mMessageNode;
	private String mDuration;
	private List<BaseNode> mChildren;
}
